package services.kingdee

import models.{KeyValue, KeyValueRepository}
import play.api.libs.json.{JsObject, JsValue, Json}
import play.api.libs.ws.{DefaultWSCookie, WSClient}
import play.api.{Configuration, Logging}

import java.time.LocalDateTime
import java.util.UUID
import javax.inject.{Inject, Singleton}
import scala.concurrent.duration.{Duration, DurationInt}
import scala.concurrent.{Await, ExecutionContext, Future}

@Singleton
class KingdeePostV1 @Inject()(ws: WSClient,
                              kvRepo: KeyValueRepository,
                              config: Configuration)(implicit exec: ExecutionContext)
  extends Logging {
  case class KingdeeWebApiForm(format: String = "1",
                               useragent: String = "ApiClient",
                               rid: String = UUID.randomUUID().toString,
                               parameters: JsValue,
                               timestamp: String = LocalDateTime.now().toString,
                               v: String = "1.0")

  implicit val outStockRevFormat = Json.format[KingdeeWebApiForm]

  var kdAppConfig = config.get[KingdeeConfig]("") // test

  def setConfig(serverUrl: String,
                dCID: String,
                userName: String,
                pwd: String = ""
               ) = {
    this.kdAppConfig = KingdeeConfig(
      serverUrl = serverUrl,
      dCID = dCID,
      userName = userName,
      pwd = pwd
    )
    this
  }

  def setConfig(dCID: String) = {
    this.kdAppConfig = config.get[KingdeeConfig](dCID)
    this
  }

  def setConfig(config:KingdeeConfig) = {
    this.kdAppConfig = config
    this
  }

  val kingdeePostApi = Map(
    "ValidateUser" -> "Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser.common.kdsvc", //# 登陆验证接口
    "View" -> "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.View.common.kdsvc", //# 查看表单数据接口
    "Save" -> "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save.common.kdsvc", //# 保存表单数据接口
    "BatchSave" -> "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.BatchSave.common.kdsvc", //# 批量保存表单数据接口
    "Submit" -> "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Submit.common.kdsvc", //# 提交表单数据接口
    "Audit" -> "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Audit.common.kdsvc", //# 审核表单数据接口
    "UnAudit" -> "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.UnAudit.common.kdsvc", //# 反审核表单数据接口
    "Delete" -> "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Delete.common.kdsvc", //# 删除表单数据接口
    "Query" -> "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc", //# 表单数据查询接口
    "StatusConvert" -> "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.StatusConvert.common.kdsvc", //# 状态转换
    "OutStockService" -> "Kingdee.K3.SCM.WebApi.ServicesStub.OutStockService.Save.common.kdsvc", //# 管易.发货单 》》 销售出库单
    "ReturnStockService" -> "Kingdee.K3.SCM.WebApi.ServicesStub.ReturnStockService.Save.common.kdsvc", //# 管易.退换货单 》》 销售退货单
    "InstockService" -> "Kingdee.K3.SCM.WebApi.ServicesStub.InstockService.Save.common.kdsvc", //# 管易.采购入库单 》》
    "PurReturnService" -> "Kingdee.K3.SCM.WebApi.ServicesStub.PurReturnService.Save.common.kdsvc" //# 管易.采购退货出库单 》》
  )

  private def login(vlogin: Boolean = true): Future[CookieDict] = {
    if (kdAppConfig.serverUrl.length <= 5) return Future(CookieDict(messages = Json.obj("success" -> false)))
    val kvKey = kdAppConfig.userName + "@" + kdAppConfig.dCID
    val kvValue = kvRepo.findBy(kvKey).map(k => (k.vValue, k.vTimestamp))
    if (kvValue.nonEmpty && vlogin && ((System.currentTimeMillis / 1000 - kvValue.head._2) < 720L)) {
      val kv = Json.parse(kvValue.head._1)
      Future(
        CookieDict(
          messages = Json.obj("success" -> true),
          aspSession = kv("ASP.NET_SessionId").as[String],
          kdSessionid = kv("kdservice-sessionid").as[String]
        ))
    } else {
      //val session_response ="""{"success":true,"ASP.NET_SessionId":"sss","kdservice-sessionid":"ssss"}"""
      // dont login post
      if (kvValue.isEmpty) kvRepo.insert(KeyValue(vKey = kvKey))
      // login post
      val data = Json.toJson(
        KingdeeWebApiForm(
          parameters = Json.parse(s"""["${kdAppConfig.dCID}","${kdAppConfig.userName}","${kdAppConfig.pwd}",${kdAppConfig.lCID}]""")))
      //      println(data)
      val response = ws.url(kdAppConfig.serverUrl + "Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser.common.kdsvc")
        .withRequestTimeout(300.second).post(data)
      response.map(res => {
        val response = Json.parse(this.loginResult(res.body))
        val message = if (response("LoginResultType").toString().toInt == 1) {
          kvRepo.update(
            KeyValue(vKey = kvKey,
              vValue = s"""{"success":true,"ASP.NET_SessionId":"${res.cookie("ASP.NET_SessionId").get.value}","kdservice-sessionid":"${res.cookie("kdservice-sessionid").get.value}"}""",
              vTimestamp = System.currentTimeMillis / 1000)
          ).map(id => println("update KeyValue id=" + id))
          Json.obj("success" -> true)
        }
        else Json.obj("success" -> false)
        CookieDict(
          aspSession = res.cookie("ASP.NET_SessionId").get.value,
          kdSessionid = res.cookie("kdservice-sessionid").get.value,
          messages = message
        )
      })
    }
  }

  def post(apiUrl: String, parameters: JsValue) = {
    //    println(parameters)
    var data: JsValue = Json.obj()
    try {
      data = Json.toJson(KingdeeWebApiForm(parameters = parameters))
    } catch {
      case exception: Exception => {
        logger.error("toJson_error:", exception)
        //        Future("""response_error:Code(-2147467259);{"InnerExWrapper":{"IsEmpty":false,"Data":{},"HelpLink":null,"Message":"调用的目标发生了异常。","Source":null,"StackTrace":" ","TargetSite":null,"ExceptionType":"System.Reflection.TargetInvocationException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","InnerException":{"IsEmpty":false,"Data":{},"HelpLink":null,"Message":"{ctx == null}","Source":null,"StackTrace":"  ","TargetSite":null,"ExceptionType":"System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","InnerException":null}},"ClassName":"Kingdee.BOS.ServiceFacade.ServiceException","Message":"{ctx == null}","Data":null,"InnerException":null,"HelpURL":null,"StackTraceString":" ","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":"8\nExecute\nKingdee.BOS.ServiceFacade.KDServiceFx, Version=7.3.1116.1, Culture=neutral, PublicKeyToken=null\nKingdee.BOS.ServiceFacade.KDServiceFx.ServiceExecutor\nSystem.String Execute(Kingdee.BOS.ServiceFacade.KDServiceFx.KDServiceContext, Kingdee.BOS.ServiceFacade.KDServiceFx.ServiceType, System.String[], Kingdee.BOS.ServiceFacade.SerializerProxy, Kingdee.BOS.ServiceFacade.KDServiceFx.ServiceType)","HResult":-2147467259,"Source":"Kingdee.BOS.ServiceFacade.KDServiceFx","WatsonBuckets":null,"_httpCode":500}""")
      }
    }
    val cookieDict = Await.result(this.login(), Duration.Inf)
    //println("post login cookieDict = " + cookieDict)
    if (!data.equals(Json.obj()) && cookieDict.messages("success").toString().toBoolean) {
      val response = ws.url(kdAppConfig.serverUrl + apiUrl)
        .addCookies(DefaultWSCookie("ASP.NET_SessionId", cookieDict.aspSession))
        .addCookies(DefaultWSCookie("kdservice-sessionid", cookieDict.kdSessionid))
        .post(data)
      response.map(r => {
        //println(r.status);
        r.body
      })
    } else {
      Future("""response_error:Code(-2147467259);{"InnerExWrapper":{"IsEmpty":false,"Data":{},"HelpLink":null,"Message":"调用的目标发生了异常。","Source":null,"StackTrace":" ","TargetSite":null,"ExceptionType":"System.Reflection.TargetInvocationException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","InnerException":{"IsEmpty":false,"Data":{},"HelpLink":null,"Message":"{ctx == null}","Source":null,"StackTrace":"  ","TargetSite":null,"ExceptionType":"System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","InnerException":null}},"ClassName":"Kingdee.BOS.ServiceFacade.ServiceException","Message":"{ctx == null}","Data":null,"InnerException":null,"HelpURL":null,"StackTraceString":" ","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":"8\nExecute\nKingdee.BOS.ServiceFacade.KDServiceFx, Version=7.3.1116.1, Culture=neutral, PublicKeyToken=null\nKingdee.BOS.ServiceFacade.KDServiceFx.ServiceExecutor\nSystem.String Execute(Kingdee.BOS.ServiceFacade.KDServiceFx.KDServiceContext, Kingdee.BOS.ServiceFacade.KDServiceFx.ServiceType, System.String[], Kingdee.BOS.ServiceFacade.SerializerProxy, Kingdee.BOS.ServiceFacade.KDServiceFx.ServiceType)","HResult":-2147467259,"Source":"Kingdee.BOS.ServiceFacade.KDServiceFx","WatsonBuckets":null,"_httpCode":500}""")
    }

  }

  def loginResult(result: String) = {
    val s = "response_error:Code(-2147467259);"
    if (result.startsWith(s))
      result.substring(33)
    else result
  }

  def webApiSave(parameters: JsValue) = this.post("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save.common.kdsvc", parameters)

  def webApiView(parameters: JsValue) = this.post("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.View.common.kdsvc", parameters)

  def webApiQuery(parameters: JsValue) = this.post("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc", parameters)

  def signCode(s: String) = s match {
    case "101" => "H"
    case "102" => "E"
    case "103" => "P"
    case "104" => "R"
    case "107" => "Z"
    case "114" => "J"
    case "201" => "L"
    case "202" => "D"
    case _ => "V"
  }
}

